/*
 * File:   Player.cpp
 * Author: jormar
 *
 * Created on 24 de mayo de 2011, 03:56 PM
 */

#include "Player.h"
#include "CSurface.h"
#include "Character.h"
#include "Behavior/AllBehavior.h"
#include "setBehavior.h"
#include "Vectores.h"
#include "CApp.h"
#include "Graph.h"
#include "Triangle.h"

#include "AnimationPlayerDown.h"
#include "AnimationPlayerUp.h"
#include "AnimationPlayerRight.h"
#include "AnimationPlayerLeft.h"

#include <math.h>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>

#include <SDL/SDL.h>
#include <SDL/SDL_gfxPrimitives.h>
#include <SDL/SDL_rotozoom.h>

Player::Player(float x, float y) {
    p[0] = 500;
    p[1] = 500;
}

Player::Player(const Player& orig) {
}

Player::~Player() {
}

bool Player::OnInit(Character* target){
  max_life = LIFE_PLAYER;
  // animaciones...
  animations.push_back(new AnimationPlayerUp());
  animations.push_back(new AnimationPlayerRight());
  animations.push_back(new AnimationPlayerDown());
  animations.push_back(new AnimationPlayerLeft());
  currentAnimation = animations[0];
  /* Posicionamos el personaje */
  k = new Kinematic();
  k->position[0] = g_player_x;
  k->position[1] = g_player_y;
  k->orientation = 0;
  k->max_velocity = 0.12;
  k->max_rotation = 0.01;
  this->width = 32;
  this->height = 16;
  life = LIFE_PLAYER;
  return true;
}

/*
 * Pinta al bicho
 */
void Player::OnRender(SDL_Surface* display){
    int fakeX, fakeY;
    int fakeW, fakeH,fakeZ,desplazamiento= 0;
    double factorK = .005;
    SDL_Surface *animationFrame, *auxFrame;
    
    Platform* p = theApp.getPlatform(k->position);
    if (p == NULL)
      fakeZ =0;
    else
      fakeZ = p->position[2];
    /// Primero una sombra
    if (p && abs(fakeZ-k->position[2]) < 1){
      fakeW = width/2;
      fakeH = height/2;
      fakeX = this->k->position[0];
      fakeY = this->k->position[1]-40;
      desplazamiento= -40;
    }
    else{
      fakeW = width/2-k->position[2]*factorK;
      fakeH = height/2-k->position[2]*factorK;
      fakeX = this->k->position[0];
      fakeY = this->k->position[1];
    }
    filledEllipseRGBA(display,
        fixX(fakeX), fixY(fakeY),
        fakeW, fakeH,
        0, 0, 0, 128
        );
    /// Puntero de direccion
    fakeX = k->position[0] + fakeW*cos(k->orientation-M_PI/2);
    fakeY = k->position[1] + fakeH*-sin(+k->orientation-M_PI/2)+desplazamiento;
    filledEllipseRGBA(display,
        fixX(fakeX), fixY(fakeY),
        width/8, height/6,
        60, 0, 0, 200
        );

    /// Sprite de la animacion
    if( length(k->velocity) < 0.000001 ){
        animationFrame = CSurface::Copy(
                currentAnimation->getFrame(),
                0, 0,
                currentAnimation->getWidth(),
                currentAnimation->getHeight()
                );
    } else {
        animationFrame = CSurface::Copy(
                currentAnimation->getFrame(),
                currentAnimation->getX(),
                currentAnimation->getY(),
                currentAnimation->getWidth(),
                currentAnimation->getHeight()
                );
    }
    fakeW = width+k->position[2]*factorK*1.2;
    fakeH = height+k->position[2]*factorK*1.2;

    // if( fakeW/width != 1.0 ){
        auxFrame = zoomSurface(animationFrame,
                fakeW/width,
                fakeH/height,
                SMOOTHING_OFF);
        SDL_FreeSurface(animationFrame);
        animationFrame = auxFrame;
        CSurface::Transparent(animationFrame, 101, 102, 103);
        zoomSurfaceSize(
                width, height,
                fakeW/width, fakeH/height,
                &fakeW, &fakeH);
    // }
    fakeX = k->position[0]-currentAnimation->getWidth()/2;
    fakeY = k->position[1]-currentAnimation->getHeight()+3-k->position[2]*.065;
    fakeX -= fakeW - width;
    fakeY -= fakeH - height;

    CSurface::OnDraw(display, animationFrame, fixX(fakeX), fixY(fakeY));
    SDL_FreeSurface(animationFrame);

    // Un pixel de control, para saber donde esta el centro
    pixelRGBA(display,
        fixX(this->k->position[0]),
        fixY(this->k->position[1]),
        255, 0, 0, 128
        );
    Sint16 x = k->position[0] - 20, y =k->position[1] - 60 - k->position[2]*.065;
    x = fixX(x);
    y = fixY(y);
    int lonRect = 40;
    const Sint16 vx[4] = {x,x,
      x+ ((float)life/LIFE_PLAYER)*lonRect,
      x+ ((float)life/LIFE_PLAYER)*lonRect};
    const Sint16 vy[4] = {y,y+5,y+5,y};

    if(life>0)
      filledPolygonColor(display,vx,vy,4,0xf41c1cff);

    rectangleColor(display,x,y,
        x+lonRect,
        y+5,0xffffffff);

    // DEBUG
//  Node *actual = theApp.findNearestNode(this->k->position);
//  cout << "Parado en Nodo " <<  actual->getId() << endl;
}

/*
 * Aplica comportamiento, actualiza la posicion
 * y anima sprites (proximamente)
 */
void Player::OnLoop(long time){
  double _3pi4 = 3*M_PI/4;
  double _pi4 = M_PI/4;
  Steering* steering = new Steering();

  // Verificamos coliciones (collides)
  float *current = (float *) malloc(sizeof(float)*3);
  float *I = (float *) malloc(sizeof(float)*3);
  float *N = (float *) malloc(sizeof(float)*3);

  if(theApp.getCollision(this, &current, &I, &N)){
    // Acomodamos la posicion del jugador inmediatamente
    k->position[0] = current[0];
    k->position[1] = current[1];
  }

  free(current);
  free(I);
  free(N);

  // Agregamos un efecto constante... gravedad
  steering->linear[2] -= 0.008;
  update(steering, time);
  delete steering;

  if(k->orientation>=_3pi4 || k->orientation<= -_3pi4){
      currentAnimation = animations[0];
  } else if(k->orientation<=_3pi4 && k->orientation>=_pi4){
      currentAnimation = animations[1];
  } else if(k->orientation<=_pi4 && k->orientation>=-_pi4){
      currentAnimation = animations[2];
  } else {
      currentAnimation = animations[3];
  }

  currentAnimation->OnAnimate();

}

void Player::OnCleanup(){

}

/* * * * * * * * * * * * * * * * * * * * */
void Player::OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode){
    switch(sym){
        case SDLK_UP:
            k->velocity[1] = -k->max_velocity;
            break;
        case SDLK_DOWN:
            k->velocity[1] = k->max_velocity;
            break;
        case SDLK_LEFT:
            k->velocity[0] = -k->max_velocity;
            break;
        case SDLK_RIGHT:
            k->velocity[0] = k->max_velocity;
            break;
        case SDLK_SPACE:
            // TODO: ajustar mejor esto a los niveles del juego
            // if( (int)k->position[2] % 400 == 0)
                k->velocity[2] = 4.5;
            break;
        default:
            break;
    }
    if( length(k->velocity) != 0 )
        k->orientation = atan2(k->velocity[0],k->velocity[1]);
}

void Player::OnKeyUp(SDLKey sym, SDLMod mod, Uint16 unicode){
    int i;
    switch(sym){
        case SDLK_UP:
            k->velocity[1] = 0;
            break;
        case SDLK_DOWN:
            k->velocity[1] = 0;
            break;
        case SDLK_LEFT:
            k->velocity[0] = 0;
            break;
        case SDLK_RIGHT:
            k->velocity[0] = 0;
            break;
        case SDLK_q:
            theApp.PikmenFree();
            break;
        default:
            break;
    }
    for(i=0; i<2; i++){
        if(k->velocity[i]!=0)
            k->velocity[i]=
                ((k->velocity[i]<0)?-1:1)*k->max_velocity;
    }
    if( length(k->velocity) != 0 )
        k->orientation = atan2(k->velocity[0],k->velocity[1]);
}

void Player::OnWheelButtonUp(int mX, int mY){
  Kinematic* current = this->getKinematic();
  current->orientation += M_PI / 16.0f;
  this->setKinematic(current);
}

void Player::OnWheelButtonDown(int mX, int mY){
  Kinematic* current = this->getKinematic();
  current->orientation -= M_PI / 16.0f;
  this->setKinematic(current);
}

void Player::OnLButtonDown(int mX, int mY){
    p[0] = mX;
    p[1] = mY;
    p[2] = 0;
    theApp.PikmenComes(p);
}
